package org.aerie.forest.core.frame.rebar.entity.bootable;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.aerie.forest.core.brick.exception.ExceptionGradeEnum;
import org.aerie.forest.core.brick.exception.ExceptionPack;
import org.aerie.forest.core.brick.exception.ForestBootableException;
import org.aerie.forest.core.brick.exception.custom.runtime.ForestRuntimeException;
import org.aerie.forest.core.frame.rebar.entity.AbstractForestRebar;
import org.aerie.forest.core.frame.rebar.entity.AbstractForestValidityCheck;

/**
 * @description forest启动器
 *
 * @author quark
 * @organization aerie
 * @date 2020年2月21日 下午2:15:50
 * @version 1.2.0
 */
public abstract class ForestBootable extends AbstractForestRebar implements BootProcessor {

	/**
	 * @description 启停组件
	 *
	 * @author quark
	 * @organization aerie
	 * @date 2020年2月21日 下午2:16:06
	 * @version 1.2.0
	 */
	protected class BootModule implements Runnable {

		/**
		 * @description 启动组件的异常信息
		 *
		 * @author quark
		 * @organization aerie
		 * @date 2020年2月21日 下午2:16:21
		 * @version 1.2.0
		 */
		protected class ExceptionInfo {

			/**
			 * @description 根本异常
			 * 
			 * @author quark
			 * @date 2020年2月21日 下午2:16:30
			 * @version 1.2.0
			 */
			private Exception primaryException;

			/**
			 * @description 异常发生的时间
			 * 
			 * @author quark
			 * @date 2020年2月21日 下午2:16:39
			 * @version 1.2.0
			 */
			private LocalDateTime exceptionTime;
		}

		/**
		 * @description 允许启动标识符
		 * 
		 * @author quark
		 * @date 2020年2月21日 下午2:26:31
		 * @version 1.2.0
		 */
		private boolean allowBootFlag = true;

		/**
		 * @description 启动标识符
		 * 
		 * @author quark
		 * @date 2020年2月21日 下午2:26:40
		 * @version 1.2.0
		 */
		private boolean bootFlag = false;

		/**
		 * @description 启动的时间
		 * 
		 * @author quark
		 * @date 2020年2月21日 下午2:26:51
		 * @version 1.2.0
		 */
		private LocalDateTime bootTime;

		/**
		 * @description 异常标识符
		 * 
		 * @author quark
		 * @date 2020年2月21日 下午2:27:03
		 * @version 1.2.0
		 */
		private boolean exceptionFlag = false;

		/**
		 * @description 异常信息集合
		 * 
		 * @author quark
		 * @date 2020年2月21日 下午2:27:24
		 * @version 1.2.0
		 */
		private List<ExceptionInfo> exceptionInfos = new ArrayList<>();

		/**
		 * @description 启动器的核心线程
		 * 
		 * @author quark
		 * @date 2020年2月21日 下午2:27:36
		 * @version 1.2.0
		 */
		private RunnableFunction runableFunction;

		/**
		 * @description 关闭触发器
		 * 
		 * @author quark
		 * @date 2020年2月21日 下午2:27:47
		 * @version 1.2.0
		 */
		private boolean closeFlag = false;

		/**
		 * @description 合法性校验块
		 * 
		 * @author quark
		 * @date 2020年5月12日 上午9:57:52
		 * @version 1.2.0
		 */
		private AbstractForestValidityCheck<ForestBootable> forestValidityCheck = new AbstractForestValidityCheck<ForestBootable>(
				"") {

			@Override
			protected void beginCheck(AbstractForestRebar forestRebar) {
				LOGGER.info("forest启动器校验");
			}
		};

		/**
		 * Construction
		 * 
		 * @param allowBootFlag   允许启动标符
		 * @param runableFunction 启动功能
		 *
		 * @date 2020年2月21日 下午2:33:55
		 * @version 1.2.0
		 */
		protected BootModule(boolean allowBootFlag, RunnableFunction runableFunction) {
			super();
			this.allowBootFlag = Optional.ofNullable(allowBootFlag).orElse(false);
			this.runableFunction = Optional.ofNullable(runableFunction)
					.orElseThrow(() -> new ForestRuntimeException("启停组件的可执行块不能为空") {

						/**
						 * @description 序列化编号
						 * 
						 * @author quark
						 * @date 2020年5月14日 上午9:43:50
						 * @version 1.2.0
						 */
						private static final long serialVersionUID = 1L;
					});
			calibrator.addValidityCheck(forestValidityCheck);
		}

		/**
		 * @description 记录异常
		 * @param exception 记录的异常
		 *
		 * @date 2020年2月21日 下午2:34:39
		 * @version 1.2.0
		 */
		private void recordException(Exception exception) {
			// TODO
		}

		/**
		 * @description 启动
		 *
		 * @date 2020年2月21日 下午2:35:42
		 * @version 1.2.0
		 */
		@Override
		public void run() {
			try {
				while (!closeFlag) {
					runableFunction.action();
				}
			} catch (Exception e) {
				disposeException(e);
			}
			// 修改启动标识符
			bootModule.bootFlag = false;
			// 重置关闭触发器
			closeFlag = false;
		}
	}

	/**
	 * @description 启动组件
	 * 
	 * @author quark
	 * @date 2020年2月21日 下午2:40:38
	 * @version 1.2.0
	 */
	protected BootModule bootModule;

	/**
	 * @description 启动器的线程
	 * 
	 * @author quark
	 * @date 2020年2月21日 下午2:40:51
	 * @version 1.2.0
	 */
	protected Thread thread;

	/**
	 * Construction
	 * 
	 * @param allowBootFlag    允许启动标识符
	 * @param forestRebarName  forest架构元素的名称
	 * @param runnableFunction 启动的功能
	 *
	 * @date 2020年2月21日 下午2:41:01
	 * @version 1.2.0
	 */
	protected ForestBootable(boolean allowBootFlag, String forestRebarName, RunnableFunction runnableFunction) {
		super(forestRebarName);
		this.bootModule = new BootModule(allowBootFlag, runnableFunction);
	}

	/**
	 * @description 获得forest架构元素的名称
	 * @return forest架构元素的名称
	 *
	 * @date 2020年2月21日 下午2:41:25
	 * @version 1.2.0
	 */
	@Override
	public String getForestRebarName() {
		return forestFrameName;
	}

	/**
	 * @description 允许启动判断
	 * @return 是否允许启动
	 *
	 * @date 2020年2月21日 下午2:41:57
	 * @version 1.2.0
	 */
	@Override
	public final boolean allowStart() {
		if ((null != bootModule && bootModule.allowBootFlag && !bootModule.bootFlag)) {
			LOGGER.debug("{}启动运行", this.getForestRebarName());
			return true;
		}
		LOGGER.trace("{}不允许启动", this.getForestRebarName());
		return false;
	}

	/**
	 * @description 关闭启动器
	 * @throws Exception 关闭启动器抛出的异常
	 *
	 * @date 2020年2月21日 下午2:43:11
	 * @version 1.2.0
	 */
	@Override
	public final synchronized void close() throws Exception {
		// 启动器启动了才可关闭
		if (bootModule.bootFlag) {
			shutDown();
			return;
		}
		LOGGER.trace("启动器没有启动无法关闭");
	}

	/**
	 * @description 启动器启动前的处理
	 *
	 * @date 2020年2月21日 下午2:43:28
	 * @version 1.2.0
	 */
	protected abstract void beforeRun();

	/**
	 * @description 启动器启动后的处理
	 *
	 * @date 2020年2月21日 下午2:43:39
	 * @version 1.2.0
	 */
	protected abstract void afterRun();

	/**
	 * @description 运行
	 * @throws Exception 不允许启动的异常，运行抛出的异常
	 *
	 * @date 2020年2月21日 下午2:43:49
	 * @version 1.2.0
	 */
	@Override
	public final synchronized void run() throws Exception {
		try {
			// 校验是否允许启动【允许启动和自定义启动条件同时达到】
			if (!allowStart() || !customAllowStart())
				throw new ForestBootableException("不符合启动条件，无法启动");
			// 执行启动前的自定义方法
			beforeRun();
			// 启动
			thread.start();
			// 修改启动标识
			bootModule.bootFlag = true;
			// 写入启动时间
			bootModule.bootTime = LocalDateTime.now();
			// 执行运行之后的自定义方法
			afterRun();
		} catch (Exception e) {
			// 记录异常
			bootModule.recordException(e);
			throw new ExceptionPack(this.getForestRebarName() + "无法运行", ExceptionGradeEnum.ERROR, e);
		}
	}

	/**
	 * @description 启动器未设置自定义启动拦截
	 * @return 自定义的启动拦截标识
	 *
	 * @date 2020年2月21日 下午2:44:22
	 * @version 1.2.0
	 */
	protected boolean customAllowStart() {
		return true;
	}

	/**
	 * @description 启动器的关闭逻辑
	 * @throws Exception 关闭启动器的自定义异常
	 *
	 * @date 2020年2月21日 下午2:44:37
	 * @version 1.2.0
	 */
	protected void shutDown() throws Exception {
		bootModule.closeFlag = true;
	}

	/**
	 * @description 获得启动标识
	 * @return 启动标识
	 *
	 * @date 2020年2月21日 下午2:47:45
	 * @version 1.2.0
	 */
	@Override
	public final boolean hasStarted() {
		return bootModule.bootFlag;
	}

	/**
	 * @description 获得启动时间
	 * @return 启动时间
	 *
	 * @date 2020年2月21日 下午2:48:08
	 * @version 1.2.0
	 */
	@Override
	public final LocalDateTime getStartTime() {

		return bootModule.bootTime;
	}

	/**
	 * @description 是否出现异常
	 * @return 异常标识符
	 *
	 * @date 2020年2月21日 下午3:07:21
	 * @version 1.2.0
	 */
	@Override
	public final boolean hasException() {

		return bootModule.exceptionFlag;
	}

	/**
	 * @description 获得根本异常
	 * @return 根本异常
	 *
	 * @date 2020年2月21日 下午3:07:37
	 * @version 1.2.0
	 */
	@Override
	public final Exception getLastPrimaryException() {

		return bootModule.exceptionInfos.get(bootModule.exceptionInfos.size() - 1).primaryException;
	}

	/**
	 * @description 获得最后异常的时间
	 * @return 最后异常的时间
	 *
	 * @date 2020年2月21日 下午3:07:50
	 * @version 1.2.0
	 */
	@Override
	public final LocalDateTime getLastExceptionTime() {

		return bootModule.exceptionInfos.get(bootModule.exceptionInfos.size() - 1).exceptionTime;
	}

	/**
	 * @description 线程是否活跃
	 * @return 线程活跃标识符
	 *
	 * @date 2020年2月21日 下午3:08:05
	 * @version 1.2.0
	 */
	@Override
	public final boolean isAlive() {
		return thread.isAlive();
	}

	/**
	 * @description 解析异常
	 *
	 * @date 2020年2月21日 下午3:08:20
	 * @version 1.2.0
	 */
	@Override
	public final void analyzeExceptions() {
		// TODO Auto-generated method stub
		// 解析异常没想好怎么处理
		LOGGER.info("待开发。。。。。。");
	}

	/**
	 * @description 异常处理
	 * @param exception 需要处理的异常
	 *
	 * @date 2020年2月21日 下午3:08:32
	 * @version 1.2.0
	 */
	protected abstract void disposeException(Exception exception);

}
